package com.ts.api.module.api.convert.core.context;

import com.alibaba.fastjson.JSONObject;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.log.Log;
import com.gitee.apanlh.util.reflection.ReflectionUtils;
import com.gitee.apanlh.util.valid.ValidParam;
import com.ts.api.module.api.convert.core.annotation.ApiMapping;
import com.ts.api.module.api.convert.core.annotation.ApiMappings;

import java.lang.annotation.Annotation;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Field;

/**
 *  字段映射上下文
 *  @author Pan
 */
public class ApiFieldMapping {

    private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();

    /** 句柄 */
    private MethodHandle methodHandle;
    /** 字段 */
    private Field field;
    /** 转换名称 */
    private String convertFieldName;
    /** 默认映射值 */
    private String defaultValue;
    /** 原值映射值 */
    private String [] sourceArray;
    /** 目标映射值 */
    private String [] targetArray;
    /** 标记是否为空注解 */
    private boolean hasNullAnn;

    ApiFieldMapping(Field field) {
        this.field = field;
        initApiMappers();
        initSetter();
    }

    private void initSetter() {
        try {
            this.methodHandle = LOOKUP.unreflectSetter(this.field);
        } catch (Throwable e) {
            Log.get().error("API字段映射获取-句柄失败", e.getMessage(), e);
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    private void initApiMappers() {
        Annotation fieldAnnotation = ReflectionUtils.getFieldAnnotation(this.field, ApiMappings.class);
        if (fieldAnnotation == null) {
            this.hasNullAnn = true;
            return ;
        }

        ApiMappings apiMappings = (ApiMappings) fieldAnnotation;
        //  获取转换字段
        this.convertFieldName = apiMappings.name();
        //  获取默认值
        this.defaultValue = apiMappings.defaultValue();

        //  获取映射值
        ApiMapping[] values = apiMappings.rules();

        this.sourceArray = new String[values.length];
        this.targetArray = new String[values.length];
        for (int i = 0; i < values.length; i++) {
            ApiMapping apiMapping = values[i];
            this.sourceArray[i] = apiMapping.k();
            this.targetArray[i] = apiMapping.v();
        }
    }

    public void apply(JSONObject form, Object sourceObj) {
        if (this.hasNullAnn) {
            return ;
        }

        String jsonValue = form.getString(this.convertFieldName);
        try {
            //  传递值空处理
            if (ValidParam.isEmpty(jsonValue)) {
                //  存在默认值直接返回默认值
                if (ValidParam.isNotEmpty(this.defaultValue)) {
                    this.methodHandle.invoke(sourceObj, this.defaultValue);
                    return ;
                }
                //  null值不处理
                return ;
            }

            //  获取映射值
            for (int i = 0; i < this.sourceArray.length; i++) {
                if (Eq.str(this.sourceArray[i], jsonValue)) {
                    this.methodHandle.invoke(sourceObj, this.targetArray[i]);
                    return ;
                }
            }

            //  无映射后但保持原传递值
            this.methodHandle.invoke(sourceObj, jsonValue);
        } catch (Throwable e) {
            Log.get().error("API字段映射获取-invoke失败", e.getMessage(), e);
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    public boolean hasNullAnn() {
        return this.hasNullAnn;
    }
}
